using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using TXLooker.Common.Debuging;

namespace TXLooker.Common.Extentions
{
    public class ExtensionLoader
    {
        private readonly IList<String> listOfAssembliesNotToLookInto;

        public ExtensionLoader()
        {
            listOfAssembliesNotToLookInto = new List<string>();
            listOfAssembliesNotToLookInto.Add("TXLooker.dll");
            listOfAssembliesNotToLookInto.Add("TXLooker.Common.dll");
            listOfAssembliesNotToLookInto.Add("TXLooker.Hooks.dll");
            listOfAssembliesNotToLookInto.Add("TXLooker.ObjectExchange.dll");
            listOfAssembliesNotToLookInto.Add("ManagedAgregator.dll");
            listOfAssembliesNotToLookInto.Add("TXLookerShim.dll");
            listOfAssembliesNotToLookInto.Add("Extensibility.dll");
            listOfAssembliesNotToLookInto.Add("Microsoft.Office.Interop.Outlook.dll");
            listOfAssembliesNotToLookInto.Add("Microsoft.TeamFoundation.dll");
            listOfAssembliesNotToLookInto.Add("Microsoft.TeamFoundation.Client.dll");
            listOfAssembliesNotToLookInto.Add("Microsoft.TeamFoundation.Common.dll");
            listOfAssembliesNotToLookInto.Add("Microsoft.TeamFoundation.Common.Library.dll");
            listOfAssembliesNotToLookInto.Add("Microsoft.TeamFoundation.VersionControl.Client.dll");
            listOfAssembliesNotToLookInto.Add("Microsoft.TeamFoundation.VersionControl.Common.dll");
            listOfAssembliesNotToLookInto.Add("Microsoft.TeamFoundation.VersionControl.Common.Integration.dll");
            listOfAssembliesNotToLookInto.Add("Microsoft.TeamFoundation.WorkItemTracking.Client.dll");
            listOfAssembliesNotToLookInto.Add("Microsoft.TeamFoundation.WorkItemTracking.Client.Cache.dll");
            listOfAssembliesNotToLookInto.Add("Microsoft.TeamFoundation.WorkItemTracking.Client.DataStore.dll");
            listOfAssembliesNotToLookInto.Add("Microsoft.TeamFoundation.WorkItemTracking.Client.Provision.dll");
            listOfAssembliesNotToLookInto.Add("Microsoft.TeamFoundation.WorkItemTracking.Client.QueryLanguage.dll");
            listOfAssembliesNotToLookInto.Add("Microsoft.TeamFoundation.WorkItemTracking.Client.RuleEngine.dll");
            listOfAssembliesNotToLookInto.Add("Microsoft.TeamFoundation.WorkItemTracking.Controls.dll");
            listOfAssembliesNotToLookInto.Add("Microsoft.TeamFoundation.WorkItemTracking.Proxy.dll");
        }

        public IList<IExtentionEntryPoint> LoadExtensions(string extensionsDirectoryPath)
        {
            List<IExtentionEntryPoint> extCollection = new List<IExtentionEntryPoint>();

            List<string> files = new List<string>();
            GetFilesByMask(extensionsDirectoryPath, false, "*.dll", ref files);
            foreach (string file in files)
            {
                try
                {
                    FileInfo assemblyFileInfo = new FileInfo(file);
                    if (!assemblyFileInfo.Exists) continue;
                    if (listOfAssembliesNotToLookInto.Contains(assemblyFileInfo.Name)) continue;

                    Assembly a = Assembly.LoadFrom(file);
                    if (a == null) continue;

                    object[] extAttributes = a.GetCustomAttributes(typeof(AssemblyExtentionAttribute), false);

                    if (extAttributes == null || extAttributes.Length == 0)
                        continue;

                    Type extEntryPointType = null;

                    foreach (Type type in a.GetTypes())
                    {
                        foreach (Type itype in type.GetInterfaces())
                        {
                            if (itype != typeof(IExtentionEntryPoint))
                                continue;

                            extEntryPointType = type;
                            break;
                        }

                        if (extEntryPointType != null)
                            break;
                    }

                    if (extEntryPointType == null)
                    {
                        string errorStr = string.Format("Appliication Extention '{0}' doesn't contain object that implement type '{1}'", file, typeof(IExtentionEntryPoint).ToString());
                        LogManager.WriteMessageToCustomLog(errorStr);
                        Debug.Assert(false, errorStr, "TX Looker");
                    }

                    if (extEntryPointType != null)
                    {
                        object obj = null;

                        try
                        {
                            obj = Activator.CreateInstance(extEntryPointType);
                        }
                        catch (System.Exception ex)
                        {
                            LogManager.WriteMessageToCustomLog(ex.ToString());
                            DebugManager.ShowErrorDescription(ex.ToString());
                        }

                        if (obj != null)
                            extCollection.Add(obj as IExtentionEntryPoint);
                    }
                    LogManager.WriteMessageToCustomLog(string.Format("Extention {0} inserted in extentions list", file));
                }
                catch (System.BadImageFormatException)
                {
                    continue;
                }
                catch (System.Exception ex)
                {
                    LogManager.WriteMessageToCustomLog(ex.ToString());
                    continue;
                }
            }
            return extCollection;
        }

        private static void GetFilesByMask(string dirpath, bool scansubdirs, string mask, ref List<string> files)
        {
            try
            {
                files.AddRange(Directory.GetFiles(dirpath, mask));

                if (!scansubdirs) return;

                foreach (string item in Directory.GetDirectories(dirpath))
                {
                    GetFilesByMask(item, true, mask, ref files);
                }
            }
            catch (System.Exception)
            {
                LogManager.WriteMessageToCustomLog("Error in files geting from " + dirpath);
            }
        }
    }
}